/*----------------------------------------------------------*
*                       Paddle Class                        *
*                                                           *
*         Created By: Matthew Hoyes  & Ronald Ram           *
*                                                           *
*      This class will eventually serve as an Abstract      *
*      Class which all other types of paddles               *
*      will inherit from, overloading the base methods.     *
*-----------------------------------------------------------*/

#region USING_STATEMENTS
//
using System;
using System.Collections;

using Microsoft.Xna.Framework;          // For Vector2
using Microsoft.Xna.Framework.Graphics; // For Texture2D
using System.Collections.Generic;
//
#endregion USING_STATEMENTS


namespace BrickBreaker.Core
{
    #region ENUMS
    //
    public enum PaddleState
    {
        IDLE,   //IDLE = Paddle can be moved left|right. Ball is still on Paddle, Game NOT STARTED
        ACTIVE  //ACTIVE = Ball has been LAUNCHED, game in-progress
    };

    public enum PaddleType
    {
        NONE,           //Ball is still on Paddle, Game NOT STARTED
        SHORT,          //Paddle becomes small, 3-sections, move faster
        NORMAL,         //Default Paddle, 5-sections
        LONG,           //Paddle becomes long, 5-sections, move slower
        SINGLE_SHOOT,   //Power-Up: 5-sections, Paddle will automatically shoot Single Barrel bullets
        DOUBLE_SHOOT,   //Power-Up: 5-sections, Paddle will automatically shoot Double Barrel bullets
        STICKY          //Power-Up: 5-sections, Ball will Stick to Paddle, use SpaceBar to launch Ball
    };

    public enum PaddleSections
    {
        NONE,   //PaddleType = Default, when ball is on Paddle, Game NOT STARTED
        THREE,  //PaddleType = SHORT
        FIVE    //PaddleType = Others...
    };

    public enum VertexLabel { A = 0, B, C, D, E, F, G, H, NONE };

    public enum PaddleSpeed
    {
        SPEED_SHORT = 10,   //Short-PaddleType Speed
        SPEED_LONG = 6,     //Long-PaddleType Speed
        SPEED_OTHERS = 8,   //Default PaddleType Speed, Game NOT STARTED. Other-PaddleType(s) Speed
        SPEED_Y_ZERO = 0    //ALWAYS: Vertical Speed = ZERO
    };

    public enum HitType 
    {
        NONE = 0,   //PaddleType = Default, when ball is on Paddle, Game NOT STARTED
        SIDE,       //When a sprite collides on one of Paddle's sides
        EDGE        //When a sprite collides with one of Paddle's vertices
    };

    //Used in labeling which direction the Colliding Sprite(Ball) is coming from
    public enum CollidingSpriteDirection { FROM_LEFT=0, FROM_RIGHT };
    
    //Visually easy way to label and describe which Paddle Slope is being used
    //public enum PaddleSlopeSides { SLOPE_LEFT, SLOPE_RIGHT };
    //
    #endregion ENUMS
    
    
    #region STRUCTS
    //
    //Track single collision Vertex and its collisionRadii
    public struct CollisionVertex
    {
        #region CONSTRUCTOR
        //Overloaded Constructor
        public CollisionVertex(Vector2 vertex, float radii) : this()
        {
            this.Vertex = new Vector2();
            this.Radii = 0.0f;

            this.Vertex = vertex;
            this.Radii = radii;
        }
        #endregion

        #region AUTO-IMPLEMENTED_PROPERTIES
        //Track Vertex(s) close to another sprite
        public Vector2 Vertex { get; set; }
        //Track collision distance between 2 sprites
        public float Radii { get; set; }
        #endregion
    }

    //Track Collision occurred on a Vertex or Side
    //If Collision on Vertex, track only one vertex in List(nearest)
    //If Collision on Side, track two vertices in List
    public struct HitSection
    {
        HitType _hitType; //= HitType.NONE;
        List<CollisionVertex> collisionVertices;

        #region CONSTRUCTOR
        //Overloaded Constructor
        public HitSection(HitType type)
        {
            this._hitType = type;
            this.collisionVertices = new List<CollisionVertex>();
        }

        //Overloaded Constructor
        public HitSection(HitType type, List<CollisionVertex> vertices)
        {
            this._hitType = type;

            this.collisionVertices = new List<CollisionVertex>();
            this.collisionVertices = vertices;
        } 
        #endregion

        #region PROPERTIES
        public HitType hitType
        {
            get { return this._hitType; }
            set { this._hitType = value; }
        }

        public List<CollisionVertex> Vertices
        {
            get { return this.collisionVertices; }
            set
            {
                collisionVertices.Clear();
                this.collisionVertices = value;
            }
        }
        #endregion

        #region METHODS
        public void Add(CollisionVertex collisionVertex)
        {
            if (collisionVertices == null)
            {
                this.collisionVertices = new List<CollisionVertex>();
            }

            collisionVertices.Add(collisionVertex);
        }
        
        //Reset Method
        public void Reset()
        {
            this._hitType = HitType.NONE;
            this.collisionVertices.Clear();
        }

        //Return Vector2 from array, based on given Index
        public Vector2 GetVertex(int index)
        {
            return this.collisionVertices[index].Vertex;
        } 
        #endregion
    }
    //
    #endregion STRUCTS



    public class BBPaddle : BBSingleSprite
    {
        #region DATA_MEMBERS
        //
        private PaddleState paddleState;        //V0--: Track current Paddle State
        private PaddleType paddleType;          //V0--: Type of Paddle used in game, Update Texture when PaddleType changes

        private PaddleSections paddleSection;   //V0--: Track how many sections Paddle is divided into, Updated: When PaddleType changes
        private List<float> sectionSizes;       //V0--: Track the size of each section, depending on how many sections Paddle is divided into(paddleSection)
        private List<Vector2> paddleVertices;   //V0--: Track location of all Vertices that make up Paddle Mesh

        private bool hasRegisteredCollision;    //V0--: Use this to track ONLY one time ComplexCollision, Reset once reflection has happened

        private Texture2D cannons;

        #region INTERNAL_COLLISION_TRACKING
        private bool isBallTrappedInsidePaddle;         //V0--: Track if paddle move trapped Sprite(ball) inside Paddle sprite
        private Vector2 adjTrappedBallPosition;         //V0--: Track and return newly adjusted position of Sprite(Ball) if trapped inside Paddle

        private List<CollisionVertex> nearest2Vertices; //V0--: Track closest 2 vertices to collision. Used in: nearestTwoVertices2Sprite() method
        private HitSection hitSection;                  //V0--: Track output from UpdateHitSection() method

        //Track vertices in Linear Eqtn for PointA and PointB
        private VertexLabel vertexLabelStart;           //V0--: PointA
        private VertexLabel vertexLabelEnd;             //V0--: PointB
        #endregion INTERNAL_COLLISION_TRACKING
        //
        #endregion DATA_MEMBERS


        #region OBJECT_CONSTRUCTION
        //
        //-------------------------------------------------------------------------------------------
        //C0--: DEFAULT Constructor
        public BBPaddle(Texture2D texture ): base(texture, Vector2.Zero)
        {
            Init();

            #region ONLY INITIALIZE, Update Later
            //
            this.hasRegisteredCollision = false;
            this.isBallTrappedInsidePaddle = false;
            this.adjTrappedBallPosition = new Vector2();

            this.sectionSizes = new List<float>();
            this.paddleVertices = new List<Vector2>();

            this.nearest2Vertices = new List<CollisionVertex>(); 
            this.hitSection = new HitSection(HitType.NONE);
            
            this.vertexLabelStart = VertexLabel.NONE;
            this.vertexLabelEnd = VertexLabel.NONE;
            //
            #endregion
        }

        //-------------------------------------------------------------------------------------------
        //Initialize Data Members
        private void Init()
        {
            base.size = new Vector2(texture.Width, texture.Height);
            //Center Paddle position, includes the offset from paddle width
            //Place 'Paddle_Ball' a bit higher on the screen so it will be bottom-flushed with actual game paddle sprite
            //since it's Height is ball + paddle height
            base.position = new Vector2((BBGlobalConfig.getWindowWidth() / 2) - (base.size.X / 2), (BBGlobalConfig.getWindowHeight() - 72));
            base.speed = new Vector2((float)PaddleSpeed.SPEED_OTHERS, (float)PaddleSpeed.SPEED_Y_ZERO);
            base.direction = Vector2.Zero;

            this.paddleState = PaddleState.IDLE;
            this.paddleType = PaddleType.NONE; //Should Be 'NONE' by default
            this.paddleSection = PaddleSections.NONE;

            //this.cannons = BBGlobalConfig.
        }
        //
        #endregion OBJECT_CONSTRUCTION



        #region PRIVATE_METHODS
        //
        //-------------------------------------------------------------------------------------------
        //M0--: Update Texture, when PaddleType changes
        private void UpdateTexture()
        {
            if (this.paddleType == PaddleType.NONE)
            {
                base.texture = BBGlobalConfig.paddle_ball;
                BBGlobalConfig.hud.AmmoActive = false;
                BBGlobalConfig.hud.Ammo = 0;
            }
            else if (this.paddleType == PaddleType.SHORT)
            {
                base.texture = BBGlobalConfig.paddle_short;
                BBGlobalConfig.hud.AmmoActive = false;
                BBGlobalConfig.hud.Ammo = 0;
            }
            else if (this.paddleType == PaddleType.NORMAL)
            {
                base.texture = BBGlobalConfig.paddle_normal;
                BBGlobalConfig.hud.AmmoActive = false;
                BBGlobalConfig.hud.Ammo = 0;
            }
            else if (this.paddleType == PaddleType.LONG)
            {
                base.texture = BBGlobalConfig.paddle_long;
                BBGlobalConfig.hud.AmmoActive = false;
                BBGlobalConfig.hud.Ammo = 0;
            }
            else if (this.paddleType == PaddleType.SINGLE_SHOOT)
            {
                base.texture = BBGlobalConfig.paddle_normal;
                this.cannons = BBGlobalConfig.singleCannon;
                BBGlobalConfig.hud.AmmoActive = true;
                BBGlobalConfig.hud.Ammo += 30;
            } 
            else if (this.paddleType == PaddleType.DOUBLE_SHOOT)
            {
                base.texture = BBGlobalConfig.paddle_normal;
                this.cannons = BBGlobalConfig.doubleCannons;
                BBGlobalConfig.hud.AmmoActive = true;
                BBGlobalConfig.hud.Ammo += 30;
            }
            //else if (this.paddleType == PaddleType.STICKY)
            //{
            ////    base.texture = BBGlobalConfig.paddle_sticky;
            //}
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Update when Texture changes
        private void UpdateSize()
        {
            base.size = new Vector2((float)base.texture.Width, (float)base.texture.Height);
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Update when PaddleType Changes
        private void UpdateSpeed()
        {
            if (this.paddleType == PaddleType.SHORT)
            {
                base.speed = new Vector2((float)PaddleSpeed.SPEED_SHORT, (float)PaddleSpeed.SPEED_Y_ZERO);
            }
            else if (this.paddleType == PaddleType.LONG)
            {
                base.speed = new Vector2((float)PaddleSpeed.SPEED_LONG, (float)PaddleSpeed.SPEED_Y_ZERO);
            }
            else
            {
                base.speed = new Vector2((float)PaddleSpeed.SPEED_OTHERS, (float)PaddleSpeed.SPEED_Y_ZERO);
            }
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Update when PaddleType changes
        private void UpdatePaddleSection()
        {
            if (this.paddleType == PaddleType.NONE)
            {
                this.paddleSection = PaddleSections.NONE;
            }
            else if (this.paddleType == PaddleType.SHORT)
            {
                this.paddleSection = PaddleSections.THREE;
            }
            else
            {
                this.paddleSection = PaddleSections.FIVE;
            }
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calc paddle section, when PaddleSection changes
        //Divides the paddle into specific sections(in Pixels)
        private void calcSectionSizes()
        {
            //Only ONE time instantiation & copy of 'sectionSizes' exists
            if (sectionSizes == null)
            {
                sectionSizes = new List<float>();
            }
            else { sectionSizes.Clear(); }

            #region UPDATE_PADDLE_SECTIONS
            switch (paddleSection)
            {
                case PaddleSections.THREE:
                    for (int i = 0; i < 3; i++)
                    {
                        sectionSizes.Add(30.0f);
                    }
                    break;

                case PaddleSections.FIVE:
                    if (paddleType == PaddleType.LONG)
                    {
                        for (int i = 0; i < 5; i++)
                        {
                            sectionSizes.Add(30.0f);
                        }
                    }
                    else
                    {
                        //Normal/Default or Other paddles
                        sectionSizes.Add(30.0f);
                        for (int i = 0; i < 3; i++)
                        {
                            sectionSizes.Add(20.0f);
                        }
                        sectionSizes.Add(30.0f);
                    }
                    break;
            }
            #endregion UPDATE_PADDLE_SECTIONS
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Update Position, after Texture, Size, Speed, PaddleSection, SectionSizes are updated
        private void UpdatePaddlePosition()
        {
            //hitting the left wall?
            if ((base.position.X - base.speed.X) <= 0)
            {
                base.position.X = 0; //yes, stop the paddle
            }
            // hitting the right wall?
            else if ((base.position.X + base.speed.X) >= calcPaddlePosX_MovementLimit2Right())
            {
                // yes, stop the paddle
                base.position.X = calcPaddlePosX_MovementLimit2Right(); //stop @ right Wall Limit;
            }

            base.position.Y = ( BBGlobalConfig.getWindowHeight() - 60 );
        }
        
        //-------------------------------------------------------------------------------------------
        //M0--: Update when PaddleSection Changes
        //IMPORTANT: Run 'calcSectionSizes()' B4 this method
        private void UpdatePaddleVertices()
        {
            float tempLenght = 0.0f;

            //Clear all PaddleVertices values, works for 'PaddleSection = NONE' too
            paddleVertices.Clear();

            #region NORMAL or LONG Paddle
            //
            if (paddleSection == PaddleSections.FIVE)
            {
                paddleVertices.Add(new Vector2(position.X, position.Y + size.Y));                                     //Point: A
                paddleVertices.Add(new Vector2((position.X + (position.X + sectionSizes[0])) / 2, ((position.Y + size.Y) + position.Y) / 2)); //Point: B
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[0]), position.Y));            //Point: C
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[1]), position.Y));            //Point: D
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[2]), position.Y));            //Point: E
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[3]), position.Y));            //Point: F
                paddleVertices.Add(new Vector2(((position.X + tempLenght) + (position.X + tempLenght + sectionSizes[4])) / 2, (position.Y + (position.Y + size.Y)) / 2)); //Point: G
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[4]), position.Y + size.Y));   //Point: H
            } 
            #endregion
            //
            #region SHORT Paddle
            //
            else if (paddleSection == PaddleSections.THREE)
            {
                paddleVertices.Add(new Vector2(position.X, position.Y + size.Y));                                     //Point: A
                paddleVertices.Add(new Vector2((position.X + (position.X + sectionSizes[0])) / 2, ((position.Y + size.Y) + position.Y) / 2)); //Point: B
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[0]), position.Y));            //Point: C
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[1]), position.Y));            //Point: D
                paddleVertices.Add(new Vector2(((position.X + tempLenght) + (position.X + tempLenght + sectionSizes[2])) / 2, (position.Y + (position.Y + size.Y)) / 2)); //Point: E
                paddleVertices.Add(new Vector2(position.X + (tempLenght += sectionSizes[2]), position.Y + size.Y));   //Point: F
            } 
            #endregion
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Update when Collision happens
        //Calc two(2) Paddle vertices, closest to a sprite (Ball)
        //private Vector2[] nearestTwoVertice2Sprite(Vector2 spriteCenter)
        private List<CollisionVertex> nearestTwoVertice2Sprite(Vector2 spriteCenter)
        {
            #region LocalVars
            Vector2[] nearest = new Vector2[2];
            nearest[0] = new Vector2(0.0f, 0.0f);
            nearest[1] = new Vector2(0.0f, 0.0f);

            nearest[1] = nearest[0] = (paddleVertices[0]);

            float temp2ndMag = 0.0f;
            Vector2 temp2ndVect = new Vector2();

            //Magnitude |AC| and |BC|
            float first = 0.0f, second = 0.0f;
            //Start from PointA
            first = second = Vector2.Distance(paddleVertices[0], spriteCenter);
            
            //Store two closest Vertices and collision radii
            List<CollisionVertex> hitVertices = new List<CollisionVertex>(); 
            #endregion

            #region FindTwoNearestVertices
            for (int i = 0; i < paddleVertices.Count; i++)
            {
                //Second Place
                if (Vector2.Distance(paddleVertices[i], spriteCenter) < second)
                {
                    second = Vector2.Distance(paddleVertices[i], spriteCenter);
                    nearest[1] = paddleVertices[i];
                    //First Place
                    if (second < first)
                    {
                        //Promote Second to First
                        temp2ndMag = first;
                        first = second;
                        second = temp2ndMag;
                        //Demote First to Second
                        temp2ndVect = nearest[0];
                        nearest[0] = paddleVertices[i];
                        nearest[1] = temp2ndVect;
                    }
                }
            }//for-loop 
            #endregion

            #region ReturnTwoNearestVertices
            first = (float)Math.Round(first, 2); //Round to 2-decimal places
            second = (float)Math.Round(second, 2);//Round to 2-decimal places
            hitVertices.Add(new CollisionVertex(nearest[0], first)); 
            hitVertices.Add(new CollisionVertex(nearest[1], second));

            return hitVertices; //return nearest; 
            #endregion
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Update when Collision happens
        //IMPORTANT: Run 'nearestTwoVertice2Sprite(sprite)' B4 this method
        //SEE ME: Might have to revisit this method for more accuracy checks...
        //private int updateHitSection(List<Vector2> vertices)
        private HitSection UpdateHitSection(List<CollisionVertex> vertices, BBSingleSprite sprite)
        {
            #region ASSIGN: hitSection for SHORT Paddle
            if (this.paddleSection == PaddleSections.THREE)
            {
                #region VertexLabel.A
                if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.A])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list
                    this.vertexLabelStart = VertexLabel.A;
                    this.vertexLabelEnd = VertexLabel.B;
                }
                #endregion

                #region VertexLabel.B
                else if ( vertices[0].Vertex == paddleVertices[(int)VertexLabel.B] )
                {
                    //Check if sprite is colliding with nearest Vertex
                    if ( vertices[0].Radii <= sprite.Size.X /2 )
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.C])
                    {
                        this.vertexLabelStart = VertexLabel.B;
                        this.vertexLabelEnd = VertexLabel.C;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.B;
                        this.vertexLabelEnd = VertexLabel.A;
                    } 
                    
                }
                #endregion

                #region VertexLabel.C
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.C])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.D])
                    {
                        this.vertexLabelStart = VertexLabel.C;
                        this.vertexLabelEnd = VertexLabel.D;
                    }
                    else
                    {
                        vertexLabelStart = VertexLabel.C;
                        vertexLabelEnd = VertexLabel.B;
                    }
                } 
                #endregion

                #region VertexLabel.D
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.D])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.E])
                    {
                        this.vertexLabelStart = VertexLabel.D;
                        this.vertexLabelEnd = VertexLabel.E;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.D;
                        this.vertexLabelEnd = VertexLabel.C;
                    }
                } 
                #endregion

                #region VertexLabel.E
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.E])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.F])
                    {
                        this.vertexLabelStart = VertexLabel.E;
                        this.vertexLabelEnd = VertexLabel.F;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.E;
                        this.vertexLabelEnd = VertexLabel.D;
                    }
                }
                #endregion

                #region VertexLabel.F
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.F])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }
                    
                    hitSection.Vertices = vertices; //Two(2) vertices in list
                    this.vertexLabelStart = VertexLabel.F;
                    this.vertexLabelEnd = VertexLabel.E;
                }
                #endregion
            }
            #endregion  ASSIGN: hitSection for SHORT Paddle
            //
            #region ASSIGN: hitSection for NORMAL/LONG Paddle
            else if (this.paddleSection == PaddleSections.FIVE)
            {
                #region VertexLabel.A
                if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.A])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else
                    {
                        hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list
                    this.vertexLabelStart = VertexLabel.A;
                    this.vertexLabelEnd = VertexLabel.B;
                }
                #endregion

                #region VertexLabel.B
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.B])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else
                    {
                        hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.C])
                    {
                        this.vertexLabelStart = VertexLabel.B;
                        this.vertexLabelEnd = VertexLabel.C;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.B;
                        this.vertexLabelEnd = VertexLabel.A;
                    }

                }
                #endregion

                #region VertexLabel.C
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.C])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else
                    {
                        hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.D])
                    {
                        this.vertexLabelStart = VertexLabel.C;
                        this.vertexLabelEnd = VertexLabel.D;
                    }
                    else
                    {
                        vertexLabelStart = VertexLabel.C;
                        vertexLabelEnd = VertexLabel.B;
                    }
                }
                #endregion

                #region VertexLabel.D
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.D])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else
                    {
                        hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.E])
                    {
                        this.vertexLabelStart = VertexLabel.D;
                        this.vertexLabelEnd = VertexLabel.E;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.D;
                        this.vertexLabelEnd = VertexLabel.C;
                    }
                }
                #endregion

                #region VertexLabel.E
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.E])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else
                    {
                        hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.F])
                    {
                        this.vertexLabelStart = VertexLabel.E;
                        this.vertexLabelEnd = VertexLabel.F;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.E;
                        this.vertexLabelEnd = VertexLabel.D;
                    }
                }
                #endregion

                #region VertexLabel.F
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.F])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.G])
                    {
                        this.vertexLabelStart = VertexLabel.F;
                        this.vertexLabelEnd = VertexLabel.G;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.F;
                        this.vertexLabelEnd = VertexLabel.E;
                    }
                }
                #endregion

                #region VertexLabel.G
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.G])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else { hitSection.hitType = HitType.SIDE;
                    }
                    
                    hitSection.Vertices = vertices; //Two(2) vertices in list

                    if (vertices[1].Vertex == paddleVertices[(int)VertexLabel.H])
                    {
                        this.vertexLabelStart = VertexLabel.G;
                        this.vertexLabelEnd = VertexLabel.H;
                    }
                    else
                    {
                        this.vertexLabelStart = VertexLabel.G;
                        this.vertexLabelEnd = VertexLabel.F;
                    }
                }
                #endregion

                #region VertexLabel.H
                else if (vertices[0].Vertex == paddleVertices[(int)VertexLabel.H])
                {
                    //Check if sprite is colliding with nearest Vertex
                    if (vertices[0].Radii <= sprite.Size.X / 2)
                    {
                        hitSection.hitType = HitType.EDGE;
                    }
                    else{ hitSection.hitType = HitType.SIDE;
                    }

                    hitSection.Vertices = vertices; //Two(2) vertices in list
                    this.vertexLabelStart = VertexLabel.H;
                    this.vertexLabelEnd = VertexLabel.G;
                }
                #endregion
            }
            #endregion ASSIGN: hitSection for NORMAL/LONG Paddle

            return hitSection;
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calc Paddle's Max RIGHT Movement Limit(B4 collision w/ Right Wall)
        private float calcPaddlePosX_MovementLimit2Right()
        {
            return (float)(BBGlobalConfig.WindowWidth - base.size.X);
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calc Distance - Normal Between a Sprite and a Bevel Side
        private float CalcDistBtwSpriteAndBevelSide(BBSingleSprite sprite)
        {
            #region LOCAL_VARS
            Vector2 pointA_Start = paddleVertices[(int)vertexLabelStart]; //nearPoints[0];
            Vector2 pointB_End = paddleVertices[(int)vertexLabelEnd];     //nearPoints[1];

            //LineAB (y = mx + b)
            float slope_AB = 0.0f;
            float yIntercept_B1 = 0.0f;
            //LineC (y = mx + b)
            float slope_C = 0.0f;
            float yIntercept_B2 = 0.0f;

            //Perpendicular Intersection Point of PointC and LineAB
            Vector2 intersectionPoint_D = new Vector2();

            float magnitude_DC = 0.0f;
            #endregion

            #region CALC-DIST_NORMAL2BEVEL
            //*************************************************************************
            // Find Linear Eqtn Of: LineAB (Y = mX + b)
            //*************************************************************************
            //1. Find Slope(m) of AB = rise/run
            slope_AB = (pointA_Start.Y - pointB_End.Y) / (pointA_Start.X - pointB_End.X);
            //-------------------------------------------------------------------
            //2. Find b of linear eqtn
            yIntercept_B1 = pointB_End.Y - (slope_AB * pointB_End.X); //Could have just as well used pointA-coordinates
            //*************************************************************************

            
            //*************************************************************************
            // Find Linear Eqtn Of: LineC _|_ to LineAB (y = mx + b)
            //*************************************************************************
            //3. Find Slope of C
            //Perpendicular Slope of LineAB is M2 = (1/(-M1))
            slope_C = 1 / (-slope_AB);
            //-------------------------------------------------------------------
            //4. Find b of linear eqtn
            yIntercept_B2 = sprite.Center.Y - (slope_C * sprite.Center.X);
            //*************************************************************************

            
            //*************************************************************************
            // Find the Intersection Coordinates (D)
            //*************************************************************************
            //Y1 = M1.X1 + B1 AND Y2 = M2.X2 + B2
            //Using SUBSTITUTION:  
            //-------------------------------------------------------------------
            //5. Find X: M1.X1 + B1 = M2.X2 + B2 OR (mX + b = mX + b)
            //In simple terms: X = (B2 - B1) / (M1 - M2)
            intersectionPoint_D.X = (yIntercept_B2 - yIntercept_B1) / (slope_AB - slope_C);
            //Find Y:
            intersectionPoint_D.Y = (slope_C * intersectionPoint_D.X) + yIntercept_B2;
            //*************************************************************************


            //*************************************************************************
            // Find Magnitude DC
            //*************************************************************************
            //Using the Pythagorean Theorem: 'C : BallCenter'
            //6. Find Magnitude of |DC| = Sqrt( (Dx - Cx)^2 + (Dy - Cy)^2 ) 
            magnitude_DC = Vector2.Distance(intersectionPoint_D, sprite.Center);
            //
            #endregion CALC-DIST_NORMAL2BEVEL

            return (float)Math.Round(magnitude_DC, 2);
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calc Relocation of Ball.Position, if trapped inside Paddle sprite
        private void RelocateBallTrappedInsidePaddle_BevelledSide(CollidingSpriteDirection spriteDirectionLabel, BBSingleSprite sprite)
        {
            //Sprite(Ball) Eqtn: y = mX + b
            float ball_X = sprite.Position.X, ball_Y = sprite.Position.Y;
            float ball_Slope = sprite.Direction.Y / sprite.Direction.X;
            float ball_B = ball_Y / (ball_Slope * ball_X);

            //Sprite(Paddle) Eqtn: y = mX + b
            Vector2 paddle_SlopeVertex = new Vector2(); 
            float paddle_Slope = (this.paddleVertices[(int)vertexLabelStart].Y - this.paddleVertices[(int)vertexLabelEnd].Y) / (this.paddleVertices[(int)vertexLabelStart].X - this.paddleVertices[(int)vertexLabelEnd].X);
            paddle_SlopeVertex = ( this.paddleVertices[(int)vertexLabelStart] - this.paddleVertices[(int)vertexLabelEnd] );
            float paddle_B = ( this.paddleVertices[(int)vertexLabelStart].Y / (paddle_Slope * this.paddleVertices[(int)vertexLabelStart].X) );

            //Find 'Intersection Vector' between Ball and Paddle 'Linear Eqtn'
            //Ball: y = mX + b, Paddle: y = mX + b, using Substitution
            //Eqtn: X = (b1 - b) / (m - m1)
            Vector2 intersecting_VertexPostion = new Vector2();
            intersecting_VertexPostion.X = (paddle_B - ball_B) / (ball_Slope - paddle_Slope);
            intersecting_VertexPostion.Y = (paddle_Slope * intersecting_VertexPostion.X) + paddle_B;

            //Re-location of Ball.Position, Un-trap Ball inside Paddle sprite
            //Eqtn: y = mX + b
            //Normal slope to Paddle bevel side: (paddleM.Y, -paddleM.X)
            Vector2 inter_SlopeVertex = new Vector2(paddle_SlopeVertex.Y, -paddle_SlopeVertex.X);

            //Track internally the relocated Ball Position
            //Intersection Vertex - Ball.Size
            if (spriteDirectionLabel == CollidingSpriteDirection.FROM_RIGHT)
            {
                //LEFT BEVEL
                this.adjTrappedBallPosition.X = intersecting_VertexPostion.X - (sprite.Size.X * inter_SlopeVertex.X);
                this.adjTrappedBallPosition.Y = intersecting_VertexPostion.Y - (sprite.Size.Y * inter_SlopeVertex.Y);
            }
            else if (spriteDirectionLabel == CollidingSpriteDirection.FROM_LEFT)
            {
                //RIGHT BEVEL
                this.adjTrappedBallPosition.X = intersecting_VertexPostion.X + (sprite.Size.X * inter_SlopeVertex.X);
                this.adjTrappedBallPosition.Y = intersecting_VertexPostion.Y - (sprite.Size.Y * inter_SlopeVertex.Y);
            }
        }

        #region CALC_REFELCTION
        //-------------------------------------------------------------------------------------------
        //M0--: Calculate Reflection: 
        //Paddle.LEFT: Ball L->R, Paddle.RIGHT: Ball R->L 
        private Vector2 BevelReflection(BBSingleSprite sprite)
        {
            //Check for Ball Trapped Inside Paddle sprite
            ////if (this.isBallTrappedInsidePaddle)
            ////{
            ////    RelocateBallTrappedInsidePaddle_BevelledSide(sprite);
            ////}

            #region CALC_REFLECTION
            Vector2 reflection = new Vector2();

            //-------------------------------------------------------------------
            //1. Find Vector_AB (delta_X, delta_Y), Slope_AB written in Vector2 format (X,Y) Not Scalar form (Rise/Run)
            Vector2 Vector_AB = (paddleVertices[(int)vertexLabelEnd] - paddleVertices[(int)vertexLabelStart]);

            //-------------------------------------------------------------------
            //2. Find Normal(N)    _|_ of LineAB: N = (delta_Y, -delta_X)
            //N written in Vector2 format (X,Y) NOT in scalar: M2 = (1/(-M1)) OR M2 = (1/(-delta_X/delta_Y))
            //Normal in Vector2 = (Y, -X) from Slope_AB in #1
            Vector2 Normal = new Vector2(Vector_AB.Y, -Vector_AB.X);

            //-------------------------------------------------------------------
            //3. Find Normalize N1: [ (delta_Y / N), ((-ve delta_X) / N) ]
            float mag_N = (float)Math.Sqrt(Math.Pow(Normal.X, 2) + Math.Pow(Normal.Y, 2));
            Vector2 Normalize_N1 = new Vector2((Normal.X / mag_N), (Normal.Y / mag_N));

            //-------------------------------------------------------------------
            //4. Find Projection = (-sprite.Direction * Normalize_N1) * Normalize_N1

            //4A. First Find (|P|)magtitude of sprite.Direction onto Normal(N), 
            //i.e: Transfrom P in same direction as N: |P| = (-sprite.Direction * Normalize_N1)
            float mag_P = Vector2.Dot((-sprite.Direction), Normalize_N1);

            //-------------------------------------------------------------------
            //4B. Calc. Projection(P) = |P| * Normalize_N1
            Vector2 projection_P = Vector2.Multiply(Normalize_N1, mag_P);

            //-------------------------------------------------------------------
            //5. Find Reflection (R): R = 2 * P + sprite.Direction
            reflection = (2 * projection_P + sprite.Direction);
            reflection.Normalize();
            reflection = new Vector2((float)Math.Round(reflection.X, 2), (float)Math.Round(reflection.Y, 2)); 
            #endregion

            return reflection;
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calculate Reflection: 
        //Paddle: LEFT side bevel, Sprite(ball) R->L
        private Vector2 BevelReflection_Adjusted_RL(BBSingleSprite sprite)
        {
            //Check for Ball Trapped Inside Paddle sprite
            ////if ( this.isBallTrappedInsidePaddle )
            ////{
            ////    RelocateBallTrappedInsidePaddle_BevelledSide(CollidingSpriteDirection.FROM_RIGHT, sprite);
            ////}

            #region CALC_REFLECTION
            Vector2 reflection = new Vector2();

            //Restrict MIN theta threshold
            if (sprite.Direction.X > -0.1f)
            {
                reflection.X = -0.70f;
                reflection.Y = -0.72f;
            }
            else
            {
                reflection.X = -sprite.Direction.Y;
                reflection.Y = sprite.Direction.X; //Don't Need (-1X), since sprite.Direction.X is already -VE
            }
            //Round Off to two decimal places
            reflection.X = (float)Math.Round(reflection.X, 2);
            reflection.Y = (float)Math.Round(reflection.Y, 2);
            #endregion

            return reflection;
        }
        
        //-------------------------------------------------------------------------------------------
        //M0--: Calculate Reflection: 
        //Paddle: RIGHT side bevel, Sprite(ball) L->R
        private Vector2 BevelReflection_Adjusted_LR(BBSingleSprite sprite)
        {
            Vector2 reflection = new Vector2();

            //Check for Ball Trapped Inside Paddle sprite
            ////if (this.isBallTrappedInsidePaddle)
            ////{
            ////    RelocateBallTrappedInsidePaddle_BevelledSide(CollidingSpriteDirection.FROM_LEFT, sprite);
            ////}

            #region CALC_REFLECTION
            //Restrict MIN theta threshold
            if (sprite.Direction.X < 0.1f)
            {
                reflection.X = 0.70f;
                reflection.Y = -0.72f;
            }
            else
            {
                reflection.X = sprite.Direction.Y;
                reflection.Y = -sprite.Direction.X;
            }
            //Round Off to two decimal places
            reflection.X = (float)Math.Round(reflection.X, 2);
            reflection.Y = (float)Math.Round(reflection.Y, 2);

            return reflection;
            #endregion
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calculate Reflection:
        //Paddle Middle: Ball L->R, Paddle Middle: Ball R->L
        private Vector2 HorizontalReflection(BBSingleSprite sprite)
        {
            Vector2 reflection = new Vector2(sprite.Direction.X, -sprite.Direction.Y);
            reflection.X = (float)Math.Round(reflection.X, 2);
            reflection.Y = (float)Math.Round(reflection.Y, 2);
            //Sprite.Direction L->R
            ////if ( sprite.Direction.X >0 && sprite.Direction.Y > 0 )
            ////{
            ////    reflection = new Vector2(sprite.Direction.X, -sprite.Direction.Y);
            ////}
            //Sprite.Direction R->L
            ////else if (sprite.Direction.X <0 && sprite.Direction.Y >0)
            ////{
            ////    reflection = new Vector2(sprite.Direction.X, -sprite.Direction.Y);
            ////}

            return reflection;
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calculate Reflection:
        //Paddle: LEFT Flat side, Sprite(ball) L->L
        private Vector2 HorizontalReflection_Adjusted_LL(BBSingleSprite sprite)
        {
            Vector2 reflection = new Vector2();

            //Restrict MIN theta threshold
            if (sprite.Direction.X < 0.2f)
            {
                reflection.X = -0.70f;
                reflection.Y = -0.72f;
            }
            else if (sprite.Direction.Y < 0.2f)
            {
                reflection.X = -0.70f;
                reflection.Y = -0.72f;
            }
            else
            {
                reflection.X = -sprite.Direction.Y;
                reflection.Y = -sprite.Direction.X;
            }
            //Round Off to two decimal places
            reflection.X = (float)Math.Round(reflection.X, 2);
            reflection.Y = (float)Math.Round(reflection.Y, 2);

            return reflection;
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Calculate Reflection:
        //Paddle: RIGHT Flat side, Sprite(ball) R->R
        private Vector2 HorizontalReflection_Adjusted_RR(BBSingleSprite sprite)
        {
            Vector2 reflection = new Vector2();

            //Restrict MIN theta threshold
            if (sprite.Direction.X > -0.2f)
            {
                reflection.X = 0.70f;
                reflection.Y = -0.72f;
            }
            else if (sprite.Direction.Y < 0.2f)
            {
                reflection.X = 0.70f;
                reflection.Y = -0.72f;
            }
            else
            {
                reflection.X = sprite.Direction.Y;
                reflection.Y = sprite.Direction.X; //Don't Need (-1X), since sprite.Direction.X is already -VE
            }
            //Round Off to two decimal places
            reflection.X = (float)Math.Round(reflection.X, 2);
            reflection.Y = (float)Math.Round(reflection.Y, 2);

            return reflection;
        }
        #endregion CALC_REFELCTION
        //
        #endregion PRIVATE_METHODS



        #region PROPERTIES
        //
        //-------------------------------------------------------------------------------------------
        //M0--: Read-Only Access
        public override Texture2D Texture
        {
            get { return base.texture; }
            //NO public 'SET' property for TEXTURE', it will be private 
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Read-Only Access
        public override Vector2 Speed
        {
            get { return base.speed; }
            //NO public 'SET' property for SPEED, it will be private 
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Read-Only Access
        public override Vector2 Size
        {
            get { return base.size; }
            //NO public 'SET' property for SIZE, it will be private 
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Get/Set PaddleState 
        public PaddleState State
        {
            get { return this.paddleState; }
            set
            {
                this.paddleState = value;

                if (this.paddleState == PaddleState.IDLE)
                {
                    Reset();
                }
                else if (this.paddleState == PaddleState.ACTIVE)
                {
                    if (this.paddleType == PaddleType.NONE)
                    {
                        this.paddleType = PaddleType.NORMAL;
                    }

                    UpdateTexture();
                    //Position may have to be handled different if only PaddleType changes and GameState = ACTIVE
                    //base.position = new Vector2((BBGlobalConfig.getWindowWidth() / 2) - (base.size.X / 2), (BBGlobalConfig.getWindowHeight() - 60));

                    UpdateSize();
                    UpdateSpeed();
                    UpdatePaddleSection();
                    calcSectionSizes();
                    UpdatePaddlePosition();
                    UpdatePaddleVertices();
                }
            }
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Get/Set PaddleType
        public PaddleType Type
        {
            get { return this.paddleType; }
            set
            {
                this.paddleType = value;

                //Update other data members - PaddleState, PaddleSection, Speed, etc
                if (this.paddleType == PaddleType.NONE)
                {
                    Reset();
                }
                else
                {
                    this.paddleState = PaddleState.ACTIVE;

                    UpdateTexture();
                    //Position may have to be handled different if only PaddleType changes and GameState = ACTIVE
                    //base.position = new Vector2((BBGlobalConfig.getWindowWidth() / 2) - (base.size.X / 2), (BBGlobalConfig.getWindowHeight() - 60));

                    UpdateSize();
                    UpdateSpeed();
                    UpdatePaddleSection();
                    calcSectionSizes();
                    UpdatePaddlePosition();
                    UpdatePaddleVertices();
                }
            }
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Get Should call and register ComplexCollision ONCE, until reflection has occured
        //this State is internally updated in: Intersects(rect), hasCollided(sprite), ComplexCollision(sprite)
        public bool HasRegisteredCollision
        {
            get { return this.hasRegisteredCollision; }
            //set { this.hasRegisteredCollision = value; }
        }
        
        //-------------------------------------------------------------------------------------------
        //M0--: Read-Only Access, to verify if Sprite(Ball) got trapped inside Paddle
        public bool IsBallTrappedInPaddle
        {
            get { return this.isBallTrappedInsidePaddle; }
        }

        //-------------------------------------------------------------------------------------------
        //M0--: Read-Only Access, return New Adjusted Position of Sprite(Ball) trapped inside Paddle
        public Vector2 AdjPos_BallTrappedInPaddle
        {
            get { return this.adjTrappedBallPosition; }
        }
        //
        #endregion PROPERTIES



        #region PUBLIC_METHODS
        //
        //-------------------------------------------------------------------------------------------
        //Reset Paddle states and data members, once Player dies
        public override bool Intersects(Rectangle rect)
        {
            //Reset hasRegisteredCollision = false once, Sprite(ball) has reflected
            if ( !base.Intersects(rect) )
            {
                this.hasRegisteredCollision = false;
                this.isBallTrappedInsidePaddle = false;
            }
            
            return base.Intersects(rect);
        }

        //-------------------------------------------------------------------------------------------
        //Reset Paddle states and data members, once Player dies
        public override void Reset()
        {
            base.texture = BBGlobalConfig.paddle_ball;

            Init();
            calcSectionSizes();
            UpdatePaddleVertices();

            this.hasRegisteredCollision = false; //Check ComplexCollision once, under ball reflects
            this.isBallTrappedInsidePaddle = false;
            this.adjTrappedBallPosition = Vector2.Zero;

            this.vertexLabelStart = VertexLabel.NONE;
            this.vertexLabelEnd = VertexLabel.NONE;
            this.nearest2Vertices.Clear();
            this.hitSection.Reset();

            //reset ammo and other powers...
        }

        //-------------------------------------------------------------------------------------------
        //Update Paddle Movement - LEFT or RIGHT, Up/F = FIRE
        public override void Move(GameTime gameTime)
        {
            #region FIRE AMMO
            
            //check 'UP' or 'F' = FireAmmo
            //if (key.UP || key.F)
            //{
            //    //FireAmmo....
            //}
            #endregion

            #region MOVE Paddle LEFT...
            if (BBGlobalConfig.keyboard.Left)
            {
                //hitting the left wall?
                if ( (base.position.X - base.speed.X) <=0 )
                {
                    base.position.X = 0; //yes, stop the paddle
                    //this.Type = PaddleType.SHORT; //testing only
                }
                else { position.X -= speed.X; }//move left
            }
            #endregion MOVE Paddle LEFT...

            #region MOVE Paddle RIGHT...
            if (BBGlobalConfig.keyboard.Right)
            {
                // hitting the right wall?
                if ( (base.position.X + base.speed.X) >=calcPaddlePosX_MovementLimit2Right() ) 
                {
                    // yes, stop the paddle
                    base.position.X = calcPaddlePosX_MovementLimit2Right(); //stop @ right Wall Limit;
                    //this.Type = PaddleType.LONG; //testing only
                }
                else { position.X += speed.X; } //move right
            }
            #endregion MOVE Paddle RIGHT...

            UpdatePaddleVertices(); //Calc paddle vertices as it Moves
        }

        //-------------------------------------------------------------------------------------------
        //Render Paddle on screen
        public override void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(base.texture, base.position, Color.White);

            if ( (paddleType == PaddleType.SINGLE_SHOOT) || (paddleType == PaddleType.DOUBLE_SHOOT) )
            {
                Vector2 pos = new Vector2(base.position.X, base.position.Y - cannons.Height);
                spriteBatch.Draw(cannons, pos, Color.White);
            }

            if (BBGlobalConfig.DisplayDebug == true)
            {
                spriteBatch.DrawString(BBGlobalConfig.font, "Paddle: (" + this.position.X + ", " + this.position.Y + "), ComplexCollision: " + this.hasRegisteredCollision, new Vector2(10, 540), Color.Black);
                spriteBatch.DrawString(BBGlobalConfig.font, "Paddle Collision Vertices = " + this.vertexLabelStart + "->" + this.vertexLabelEnd + ", " + this.hitSection.hitType, new Vector2(10, 10), Color.Black);
            }
        }
        
        //-------------------------------------------------------------------------------------------
        //Firstly, check for SimpleCollision, Secondly, check for collision in beveled area
        //IMPORTANT: 'updateHitSection()' maybe the culprit...
        public bool hasCollided(BBSingleSprite sprite)
        {
            bool hasCollided = false;
            this.hitSection.Reset(); //Reset all Collision Data, before assigning new data
            
            List<CollisionVertex> nearPoints = new List<CollisionVertex>(nearestTwoVertice2Sprite(sprite.Center));
            hitSection = UpdateHitSection(nearPoints, sprite);

            //FOR SURE: HitType.EDGE - Sprite collided with a Paddle vertex 
            if ( hitSection.hitType == HitType.EDGE )
            {
                hasCollided = true;
            }
            //Check Sprite collded with a Paddle Bevel Side
            else
            {
                #region LOCAL_VARS
                float radius = sprite.Size.Y / 2;
                float magnitude = 0.0f;
                #endregion

                #region PaddleSections.THREE
                if ( this.paddleSection == PaddleSections.THREE )
                {
                    //Check for Collision on Bevel side
                    if (vertexLabelStart == VertexLabel.A ||
                        vertexLabelStart == VertexLabel.B ||
                        (vertexLabelStart == VertexLabel.C && vertexLabelEnd == VertexLabel.B) ||
                        (vertexLabelStart == VertexLabel.D && vertexLabelEnd == VertexLabel.E) ||
                        vertexLabelStart == VertexLabel.E ||
                        vertexLabelStart == VertexLabel.F
                        )
                    {
                        //Collision Check on Slope
                        magnitude = CalcDistBtwSpriteAndBevelSide(sprite);
                        if (radius >= magnitude)
                        {
                            hasCollided = true; //there is collision
                            
                            //Check Sprite(ball) is trapped inside Paddle obj
                            if (radius > magnitude)
                            {
                                this.isBallTrappedInsidePaddle = true;
                            }
                        }
                    }
                    else
                    {
                        //Check for Collision on Flat Side
                        if ( (sprite.Center.Y + radius) >= base.position.Y )
                        {
                            hasCollided = true; //there is collision

                            //Check Sprite(ball) is trapped inside Paddle obj
                            ////if ( (sprite.Center.Y + radius) > base.position.Y )
                            ////{
                            ////    this.isBallTrappedInsidePaddle = true;
                            ////}
                        }
                    }
                }
                #endregion PaddleSections.THREE

                #region PaddleSections.FIVE
                else if ( this.paddleSection == PaddleSections.FIVE )
                {
                    //Check for Collision on Bevel side
                    if (vertexLabelStart == VertexLabel.A ||
                        vertexLabelStart == VertexLabel.B ||
                        (vertexLabelStart == VertexLabel.C && vertexLabelEnd == VertexLabel.B) ||
                        (vertexLabelStart == VertexLabel.F && vertexLabelEnd == VertexLabel.G) ||
                        vertexLabelStart == VertexLabel.G ||
                        vertexLabelStart == VertexLabel.H
                        )
                    {
                        //Collision Check on Slope
                        magnitude = CalcDistBtwSpriteAndBevelSide(sprite);
                        if ( radius >= magnitude )
                        {
                            hasCollided = true; //there is collision

                            //Check Sprite(ball) is trapped inside Paddle obj
                            if (radius > magnitude)
                            {
                                this.isBallTrappedInsidePaddle = true;
                            }
                        }
                    }
                    else
                    {
                        //Check for Collision on Flat Side
                        if ( (sprite.Center.Y + radius) >= base.position.Y )
                        {
                            hasCollided = true; //there is collision

                            //Check Sprite(ball) is trapped inside Paddle obj
                            ////if ( (sprite.Center.Y + radius) > base.position.Y )
                            ////{
                            ////    this.isBallTrappedInsidePaddle = true;
                            ////}
                        }
                    }
                }
                #endregion PaddleSections.FIVE
            }
            //Reset hasRegisteredCollision = false once, Sprite(ball) has reflected
            if ( !hasCollided )
            {
                this.hasRegisteredCollision = false;
                this.isBallTrappedInsidePaddle = false;
            }
            //
            return hasCollided;
        }

        //-------------------------------------------------------------------------------------------
        //If hasCollided == YES, then calc the Reflection Angle
        public Vector2 ComplexCollision(BBSingleSprite sprite)
        {
           Vector2 reflectVector = new Vector2(0.0f, 0.0f);
            
            #region PaddleSections.THREE
            if ( this.paddleSection == PaddleSections.THREE )
            {
                //LEFT: Edge Collision: Vertex A, B, C
                if (vertexLabelStart == VertexLabel.A ||
                    vertexLabelStart == VertexLabel.B ||
                    (vertexLabelStart == VertexLabel.C && vertexLabelEnd == VertexLabel.B)
                    )
                {
                    //Ball Sprite coming from Left->Right direction
                    if (sprite.Direction.X > 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection(sprite);
                    }
                    //Ball Sprite coming from Right->Left direction
                    else if (sprite.Direction.X <= 0 && sprite.Direction.Y >= 0)
                    {
                        reflectVector = BevelReflection_Adjusted_RL(sprite);
                    }
                }
                //RIGHT: Edge Collision: Vertex D, E, F
                else if ((vertexLabelStart == VertexLabel.D && vertexLabelEnd == VertexLabel.E) ||
                        vertexLabelStart == VertexLabel.E ||
                        vertexLabelStart == VertexLabel.F
                        )
                {
                    //Ball Sprite coming from Left->Right direction
                    if (sprite.Direction.X >= 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection_Adjusted_LR(sprite);
                    }
                    //Ball Sprite coming from Right->Left direction
                    else if (sprite.Direction.X < 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection(sprite);
                    }
                }
                //MIDDLE: Flat Edge Collision: Vertex C, D
                else if ((vertexLabelStart == VertexLabel.C && vertexLabelEnd == VertexLabel.D) ||
                          (vertexLabelStart == VertexLabel.D && vertexLabelEnd == VertexLabel.C)
                        )
                {
                    reflectVector = HorizontalReflection(sprite);
                }
            }
            #endregion PaddleSections.THREE

            #region PaddleSections.FIVE
            else if (this.paddleSection == PaddleSections.FIVE)
            {
                //LEFT: Edge Collision: Vertex A, B, C
                if (vertexLabelStart == VertexLabel.A ||
                    vertexLabelStart == VertexLabel.B ||
                    (vertexLabelStart == VertexLabel.C && vertexLabelEnd == VertexLabel.B)
                    )
                {
                    //Ball Sprite coming from Left->Right direction
                    if (sprite.Direction.X > 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection(sprite);
                    }
                    //Ball Sprite coming from Right->Left direction
                    else if (sprite.Direction.X <= 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection_Adjusted_RL(sprite);
                    }
                }
                //RIGHT: Edge Collision: Vertex F, G, H
                else if ( (vertexLabelStart == VertexLabel.F && vertexLabelEnd == VertexLabel.G) ||
                            vertexLabelStart == VertexLabel.G ||
                            vertexLabelStart == VertexLabel.H
                         )
                {
                    //Ball Sprite coming from Left->Right direction
                    if (sprite.Direction.X >= 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection_Adjusted_LR(sprite);
                    }
                    //Ball Sprite coming from Right->Left direction
                    else if (sprite.Direction.X < 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = BevelReflection(sprite);
                    }
                }
                //MIDDLE LEFT: Flat Edge Collision: Vertex C, D
                else if ( (vertexLabelStart == VertexLabel.C && vertexLabelEnd == VertexLabel.D) ||
                        (vertexLabelStart == VertexLabel.D && vertexLabelEnd == VertexLabel.C)
                        )
                {
                    //Ball Sprite coming from Left->Right direction
                    if (sprite.Direction.X >= 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = HorizontalReflection_Adjusted_LL(sprite);
                    }
                    //Ball Sprite coming from Right->Left direction
                    else if (sprite.Direction.X < 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = HorizontalReflection(sprite);
                    }
                }
                //MIDDLE: Flat Edge Collision: Vertex D, E
                else if ( (vertexLabelStart == VertexLabel.D && vertexLabelEnd == VertexLabel.E) ||
                        (vertexLabelStart == VertexLabel.E && vertexLabelEnd == VertexLabel.D)
                        )
                {
                    reflectVector = HorizontalReflection(sprite);
                }
                //MIDDLE RIGHT: Flat Edge Collision: Vertex E, F
                else if ( (vertexLabelStart == VertexLabel.E && vertexLabelEnd == VertexLabel.F) ||
                           (vertexLabelStart == VertexLabel.F && vertexLabelEnd == VertexLabel.E)
                         )
                {
                    //Ball Sprite coming from Left->Right direction
                    if (sprite.Direction.X > 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = HorizontalReflection(sprite);
                    }
                    //Ball Sprite coming from Right->Left direction
                    else if (sprite.Direction.X <= 0 && sprite.Direction.Y > 0)
                    {
                        reflectVector = HorizontalReflection_Adjusted_RR(sprite);
                    }
                }
            }
            #endregion PaddleSections.FIVE

            //Set hasRegisteredCollision = true, so ONLY once reflection is calculated
            //Sprite(ball) reflected diection
            this.hasRegisteredCollision = true;
            //
            return reflectVector;
        }
        //
        #endregion PUBLIC_METHODS

    }//class
}//namespace
